﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Yoozoo.HRP.Runtime;
using Yoozoo.Managers.ResourceManagerV2.Runtime;
using Yoozoo.Mars.Got;

namespace Yoozoo.Core.Common {
    public class QualityManager : MonoBehaviour
    {
        [SerializeField]
        public List<QualityAdjusterSetting> adjusterSettings;
        public QualityAdjusterSetting currentAdjusterSetting;
        private Dictionary<int, QualityAdjusterSetting> _adjusterSettingMap;
        [SerializeField]
        private int listenerCount;
        private List<IQualityListener> _qualityListeners;
        public List<IQualityListener> QualityListeners => _qualityListeners;
        [SerializeField]
        private List<Behaviour> qualityListenerMonos;

        [SerializeField]
        private QualityEnum currentQuality = QualityEnum.None;

        public QualityEnum CurrentQuality => currentQuality;
        public int QualityValue => (int)currentQuality;

        private Dictionary<string, IQualityListener> _markQualityListenerMap;

        public bool Inited = false;
        
        public static QualityManager Inst
        {
            get
            {
                return instance;
            }

            set
            {
                instance = value;
                instance.Init();

                var qs = instance.gameObject.GetComponentsInChildren<QualityListenerMono>(true);
                foreach (var listenerMono in qs)
                {
                    listenerMono.SetActive(true);
                }

                var cameraManager = FindObjectOfType<HCameraManager>();
                if (cameraManager && cameraManager.qualityListenerMonos!=null)
                {
                    foreach (var listenerMono in cameraManager.qualityListenerMonos)
                    {
                        listenerMono.enabled = true;
                    }
                }
            }
        }

        private static QualityManager instance;

#if UNITY_EDITOR

        //private void Update()
        //{
            // DEBUG
            // if (Input.GetKeyDown(KeyCode.Space))
            // {
            //     QualityHelper.ApplyRenderPrecisionAdjuster(0);
            // }
        //}

#endif

        private void Init()
        {
            _qualityListeners = new List<IQualityListener>(10);
            qualityListenerMonos = new List<Behaviour>(10);
            _markQualityListenerMap = new Dictionary<string, IQualityListener>(10);

            _adjusterSettingMap = new Dictionary<int, QualityAdjusterSetting>();
            foreach (var setting in adjusterSettings)
            {
                _adjusterSettingMap[(int)setting.quality] = setting;
            }
            
            DeviceQuality.Instance.RegisterAction(OnQualityChange);
            //OnQualityChange(DeviceQuality.Instance.GetCurrentQuality());
        }

        public QualityAdjusterSetting GetQualityAdjusterSetting(int quality)
        {
            foreach (var setting in adjusterSettings)
            {
                if ((int)setting.quality == quality)
                {
                    return QualityAdjusterSetting.Clone(setting);
                }
            }
            return null;
        }

        public QualityAdjusterLimit GetQualityAdjusterLimit(int quality)
        {
            _adjusterSettingMap.TryGetValue(quality, out var adjusterSetting);
            if (adjusterSetting!=null)
            {
                return adjusterSetting.adjusterLimit;
            }
            return null;
        }
        /// <summary>
        /// 玩家信息面板更改调用
        /// </summary>
        /// <param name="quality"></param>
        private void OnQualityChange(QualityEnum quality)
        {
            InitQualitySetting(quality);
            ApplyQualitySetting(true);
        }

        public void InitQualitySetting(int quality)
        {
            InitQualitySetting((QualityEnum)quality);
        }
        public void InitQualitySetting(QualityEnum quality)
        {
            if (quality != QualityEnum.None)
            {
                foreach (var setting in adjusterSettings)
                {
                    if (setting.quality == quality)
                    {
                        currentAdjusterSetting = QualityAdjusterSetting.Clone(setting);
                        break;
                    }
                }
                QualityHelper.SetCurrentAdjusterSetting(quality);
                if (!Inited)
                {
                    Inited = true;
                    QualityHelper.InitAdjusterParams(quality);
                }
            }
            
            currentQuality = quality;
        }
        // 可能来自Lua直接调用。。
        public void ApplyQualitySetting(bool changeQuality = true)
        {
            DevicesGrading.Instance.SaveQuality2PlayerPrefs((int)currentQuality);

            IQualityListener resolutionAdjuster = null;
            if (_qualityListeners.Count > 0)
            {
                // 先改变分辨率，后面相机的渲染缩放再根据分辨率进行更改
                for (int i = _qualityListeners.Count - 1; i >= 0; i--)
                {
                    if (_qualityListeners[i]!=null && (_qualityListeners[i] is IRenderResolutionAdjuster))
                    {
                        if (changeQuality) 
                        {
                            _qualityListeners[i].OnChangeQuality(currentQuality);
                        }
                        QualityHelper.ApplyAdjuster(_qualityListeners[i]);
                        resolutionAdjuster = _qualityListeners[i];
                        _qualityListeners.RemoveAt(i);
                        break;
                    }
                }
                
                for (int i = _qualityListeners.Count - 1; i >= 0; i--)
                {
                    if (_qualityListeners[i] == null)
                    {
                        _qualityListeners.RemoveAt(i);
                    }
                    else
                    {
                        if (changeQuality)
                        {
                            _qualityListeners[i].OnChangeQuality(currentQuality);
                        }
                        QualityHelper.ApplyAdjuster(_qualityListeners[i]);
                    }
                }
                
                _qualityListeners.Add(resolutionAdjuster);
            }

            if (qualityListenerMonos.Count > 0)
            {
                for (int i = qualityListenerMonos.Count - 1; i >= 0; i--)
                {
                    if (qualityListenerMonos[i] == null)
                    {
                        qualityListenerMonos.RemoveAt(i);
                    }
                }
            }
        }
        
        
        public void AddQualityListener(QualityListenerMono listenerMono)
        {
            if (listenerMono == null) return;
            AddQualityListener((IQualityListener)listenerMono);
            if (!qualityListenerMonos.Contains(listenerMono))
            {
                qualityListenerMonos.Add(listenerMono);
            }
            
            if (!string.IsNullOrEmpty(listenerMono.markString))
            {
                _markQualityListenerMap[listenerMono.markString] = listenerMono;
            }
        }
    
        public void AddQualityListener(IQualityListener listener)
        {
            if (listener == null) return;
            if (!_qualityListeners.Contains(listener))
            {
                _qualityListeners.Add(listener);
                if (currentQuality != QualityEnum.None)
                {
                    listener.OnChangeQuality(currentQuality);
                    QualityHelper.ApplyAdjuster(listener);
                }
            }
            listenerCount = _qualityListeners.Count;
        }
        
        public void RemoveQualityListener(QualityListenerMono listenerMono)
        {
            if (listenerMono == null) return;
            RemoveQualityListener((IQualityListener)listenerMono);
            if (qualityListenerMonos.Contains(listenerMono))
            {
                qualityListenerMonos.Remove(listenerMono);
            }

            if (!string.IsNullOrEmpty(listenerMono.markString))
            {
                if (_markQualityListenerMap.ContainsKey(listenerMono.markString))
                {
                    _markQualityListenerMap.Remove(listenerMono.markString);
                } 
            }
        }
        
        public void RemoveQualityListener(IQualityListener listener)
        {
            if (listener == null) return;
            if (_qualityListeners.Contains(listener))
            {
                _qualityListeners.Remove(listener);
            }
            listenerCount = _qualityListeners.Count;
        }


        public T GetMarkQualityListener<T>(string mark) where T : class,IQualityListener
        {
            IQualityListener listener = null;
            if (_markQualityListenerMap.TryGetValue(mark,out listener))
            {
                return (T)listener;
            }
            return null;
        }

#if UNITY_EDITOR
        private void OnValidate()
        {
            if (adjusterSettings!=null)
            {
                adjusterSettings.Sort((a, b) =>
                {
                    return a.quality - b.quality;
                });
            }
        }

        private void OnApplicationQuit()
        {
            DeviceQuality.Instance.UnRegisterAction(OnQualityChange);
            _qualityListeners?.Clear();
            qualityListenerMonos?.Clear();
            _markQualityListenerMap?.Clear();
            _adjusterSettingMap?.Clear();
        }
#endif
    }
}

